package com.eastedu.report.principal.assemble;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.eastedu.common.enums.DateCodeType;
import com.eastedu.common.enums.SubjectType;
import com.eastedu.report.common.enums.JoinType;
import com.eastedu.report.common.model.parameter.ReportGenerateParameter;
import com.eastedu.report.common.model.po.CommonDimensionEntity;
import com.eastedu.report.common.model.po.TeacherTeachingActivityResourceJoinDetailPO;
import com.eastedu.report.common.model.po.TeacherTeachingActivityResourceJoinPO;
import com.eastedu.report.common.model.po.TeacherTeachingActivityResourceUsagePeriodSubjectPO;
import com.eastedu.report.common.util.NumberFormatUtil;
import com.eastedu.report.common.util.SqlUtil;
import com.eastedu.report.mapper.TeacherTeachingActivityResourceJoinDetailMapper;
import com.eastedu.report.mapper.TeacherTeachingActivityResourceJoinMapper;
import com.eastedu.report.mapper.TeacherTeachingActivityResourceUsageMapper;
import com.eastedu.report.principal.converter.PrincipalTeachingActivityConverter;
import com.eastedu.report.principal.model.teacher.research.TeacherTeachingActivityResourceJoinReportData;
import com.eastedu.report.principal.model.teacher.student.TeacherStudentJoinResourceDetailReportData;
import com.eastedu.report.principal.model.teacher.student.TeacherStudentReportDataContainer;
import com.eastedu.report.principal.model.teacher.student.TeacherStudentUsageReportData;
import com.eastedu.report.principal.util.ReportChartUtil;
import com.eastedu.report.principal.util.ReportDescriptionUtil;
import com.eastedu.template.chart.ChartMetadata;
import com.eastedu.template.util.ChartDataUtil;
import com.eastedu.utils.DateUtil;
import com.google.common.collect.Maps;
import lombok.Getter;
import org.springframework.stereotype.Service;

import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 教师资源应用分析 - 学生活动
 *
 * @author superman
 */
@Service
public class TeacherStudentReportDataAssembly implements ReportDataAssembly {

    private final TeacherTeachingActivityResourceJoinMapper teacherTeachingActivityResourceJoinMapper;
    private final TeacherTeachingActivityResourceUsageMapper teacherTeachingActivityResourceUsageMapper;
    private final TeacherTeachingActivityResourceJoinDetailMapper teacherTeachingActivityResourceJoinDetailMapper;
    private final PrincipalTeachingActivityConverter principalTeachingActivityConverter;

    /**
     * Instantiates a new Teacher Student report data assembly.
     *
     * @param teacherTeachingActivityResourceJoinMapper       the teacher teaching activity resource join mapper
     * @param teacherTeachingActivityResourceUsageMapper      the teacher teaching activity resource usage mapper
     * @param teacherTeachingActivityResourceJoinDetailMapper the teaching activity teacher resource join detail mapper
     * @param principalTeachingActivityConverter              the principal teaching activity converter
     */
    public TeacherStudentReportDataAssembly(TeacherTeachingActivityResourceJoinMapper teacherTeachingActivityResourceJoinMapper, TeacherTeachingActivityResourceUsageMapper teacherTeachingActivityResourceUsageMapper, TeacherTeachingActivityResourceJoinDetailMapper teacherTeachingActivityResourceJoinDetailMapper, PrincipalTeachingActivityConverter principalTeachingActivityConverter) {
        this.teacherTeachingActivityResourceJoinMapper = teacherTeachingActivityResourceJoinMapper;
        this.teacherTeachingActivityResourceUsageMapper = teacherTeachingActivityResourceUsageMapper;
        this.teacherTeachingActivityResourceJoinDetailMapper = teacherTeachingActivityResourceJoinDetailMapper;
        this.principalTeachingActivityConverter = principalTeachingActivityConverter;
    }

    /**
     * Assemble map.
     *
     * @param parameter     the parameter
     * @param schoolPeriods the school periods
     * @param subjects      the subjects
     * @return the map
     */
    @Override
    public Map<String, Object> assemble(ReportGenerateParameter parameter, List<String> schoolPeriods, List<String> subjects) {
        DateCodeType codeType = parameter.getCodeType();
        Integer dateCode = parameter.getDateCode();
        Integer termDateCode = codeType.toTerm(dateCode);
        Map<String, Object> map = Maps.newHashMap();
        TeacherStudentReportDataContainer container = getContainer(parameter, codeType, dateCode);

        TeacherTeachingActivityResourceJoinReportData studentJoinReportData = container.getStudentJoinReportData();
        //        1、本月未开展学生活动，则输出：
        //        本月学生活动参与情况：本月暂未开展学生活动。
        //
        //        2、本月开展了学生活动，且均以直播形式开展的，则输出：
        //        本月学生活动参与情况：本月共计开展了xx场学生活动，均以直播形式开展。本校教师共计参与了xx场，其中直播参与了xx场，回看参与了xx场，学生活动直播参与率为xx.x%，学生活动总参与率为xx.x%。
        //
        //        3、本月开展了学生活动，有点播的、有以直播形式开展的，则输出：
        //        本月学生活动参与情况：本月共计开展了xx场学生活动，其中xx场以直播形式开展，xx场以点播形式开展。以直播形式开展的学生活动中，本校教师共计参与了xx场，其中直播参与了xx场，回看参与了xx场。以点播形式开展的学生活动汇总，本校教师共计参与了xx场。本月，本校教师学生活动直播参与率为xx.x%，总参与率为xx.x%。
        //        直播参与了xx场、回看参与了xx场：这2句话根据参与情况对应输出，参与情况有，就输出，没有就不输出。

        map.put("teacher_student_resource_usage_number_month_desc", DescriptionLevel.determineDescription(studentJoinReportData));

        // 是否显示表格：本月学生活动教师参与情况
        map.put("teacher_student_resource_usage_number_month_table_show", Objects.nonNull(studentJoinReportData)
                && Objects.nonNull(studentJoinReportData.getResourceReceiveNumber())
                && studentJoinReportData.getResourceReceiveNumber() > 0);
        // 表格： 本月学生活动教师参与情况
        LongAdder counter = new LongAdder();
        map.put("teacher_student_resource_usage_number_month_table", container.getJoinResourceDetailReportDataList().stream()
                .collect(Collectors.groupingBy(TeacherStudentJoinResourceDetailReportData::getResourceName))
                .entrySet()
                .stream()
                .map(entry -> {
                    counter.increment();
                    List<TeacherStudentJoinResourceDetailReportData> data = entry.getValue();
                    Map<String, Object> m = Maps.newHashMap();
                    m.put("order", counter.intValue());
                    m.put("name", entry.getKey());
                    m.put("school_period", data.stream().map(TeacherStudentJoinResourceDetailReportData::getSchoolPeriod).sorted().collect(Collectors.joining(",")));
                    m.put("subject", data.stream()
                            .map(TeacherStudentJoinResourceDetailReportData::getSubjectCode)
                            .map(code -> Arrays.stream(code.split(","))
                                    .map(SubjectType::getByCode).collect(Collectors.toList()))
                            .flatMap(Collection::parallelStream)
                            .sorted(Comparator.comparing(Enum::ordinal))
                            .map(SubjectType::getName)
                            .collect(Collectors.joining(",")));
                    m.put("activity_time", data.stream().map(TeacherStudentJoinResourceDetailReportData::getResourceTime).findFirst().map((timestamp) -> DateUtil.getDateFormatByTimestamp(timestamp, "yyyy/MM/dd")).orElse("-"));
                    m.put("state", data.stream().map(TeacherStudentJoinResourceDetailReportData::getJoinStatus).map(status -> JoinType.getJoinType(status).getDesc()).findFirst().orElse("未参与"));
                    return m;
                }).collect(Collectors.toList())
        );

        List<ChartMetadata> subjectMetadata = ChartDataUtil.convertSubject(subjects);
        List<ChartMetadata> chartMetadata = ChartDataUtil.convertPeriod(schoolPeriods, Comparator.comparingInt(ChartMetadata::getOrder).reversed());
        List<TeacherStudentUsageReportData> termUsages = container.getUsageReportDataList().stream().filter(data -> DateCodeType.TERM.equals(data.getCodeType())).collect(Collectors.toList());
        // xx-xx学年（上/下）同步资源教师使用率
        String schoolYear = DateUtil.convertTermToSchoolYear(String.valueOf(termDateCode));
        map.put("teacher_student_resource_usage_rate_term_desc", Description.RATE.createResourceUsageDescription(termUsages.stream().filter(data -> Objects.nonNull(data.getSchoolPeriod())).collect(Collectors.toList()),
                                                                                                                 data -> Objects.nonNull(data.getFollowedResourceUseRate()) && data.getFollowedResourceUseRate() > 0.0,
                                                                                                                 TeacherStudentUsageReportData::getFollowedResourceUseRate));
        // 2023-2024学年（上）各年级学科学生活动环节教师同步资源使用率
        chartMetadata.sort(Comparator.comparing(ChartMetadata::getOrder));
        long count = termUsages.stream().map(TeacherStudentUsageReportData::getFollowedResourceUseRate)
                .filter(Objects::nonNull)
                .filter(num -> num > 0)
                .count();
        map.put("teacher_student_resource_usage_term_chart_show", count > 0);
        map.put("teacher_student_resource_usage_term_chart", ReportChartUtil.chart(schoolYear + "各年级学科学生活动环节教师同步资源使用率",
                                                                                   subjectMetadata,
                                                                                   chartMetadata,
                                                                                   termUsages,
                                                                                   TeacherStudentUsageReportData::getFollowedResourceUseRate));
        return map;
    }

    private TeacherStudentReportDataContainer getContainer(ReportGenerateParameter parameter, DateCodeType codeType, Integer dateCode) {


        TeacherStudentReportDataContainer container = new TeacherStudentReportDataContainer();
        container.setStudentJoinReportData(this.getTeacherTeachingActivityResourceJoinReportData(parameter));
        container.setUsageReportDataList(this.getTeacherStudentUsageReportData(parameter, codeType, dateCode));
        container.setJoinResourceDetailReportDataList(this.getTeacherStudentJoinResourceDetailReportData(parameter));
        return container;
    }

    private List<TeacherStudentUsageReportData> getTeacherStudentUsageReportData(ReportGenerateParameter parameter, DateCodeType codeType, Integer dateCode) {
        LambdaQueryWrapper<TeacherTeachingActivityResourceUsagePeriodSubjectPO> wrapper = SqlUtil.queryWrapper(parameter,
                                                                                                               w -> w.and(c ->
                                                                                                                                  c.or(a -> a.eq(CommonDimensionEntity::getCodeType, codeType).eq(CommonDimensionEntity::getDateCode, dateCode))
                                                                                                                                          .or(a -> a.eq(CommonDimensionEntity::getCodeType, DateCodeType.TERM).eq(CommonDimensionEntity::getDateCode, DateUtil.getCurrentTermDateCode(DateUtil.getLastMonthLocalDate()))))
                                                                                                                       .eq(TeacherTeachingActivityResourceUsagePeriodSubjectPO::getTeachingActivity, "学生活动"),
                                                                                                               TeacherTeachingActivityResourceUsagePeriodSubjectPO.class);
        List<TeacherTeachingActivityResourceUsagePeriodSubjectPO> pos = teacherTeachingActivityResourceUsageMapper.selectList(wrapper);
        return principalTeachingActivityConverter.convertToTeacherStudentTeacherResourceUsageReportData(pos);
    }

    private TeacherTeachingActivityResourceJoinReportData getTeacherTeachingActivityResourceJoinReportData(ReportGenerateParameter parameter) {
        LambdaQueryWrapper<TeacherTeachingActivityResourceJoinPO> wrapper = SqlUtil.queryWrapper(parameter,
                                                                                                 w -> w.eq(CommonDimensionEntity::getCodeType, parameter.getCodeType())
                                                                                                         .eq(CommonDimensionEntity::getDateCode, parameter.getDateCode())
                                                                                                         .eq(TeacherTeachingActivityResourceJoinPO::getTeachingActivity, "学生活动"),
                                                                                                 TeacherTeachingActivityResourceJoinPO.class);
        List<TeacherTeachingActivityResourceJoinPO> pos = teacherTeachingActivityResourceJoinMapper.selectList(wrapper);
        TeacherTeachingActivityResourceJoinPO po = pos.stream().findFirst().orElse(null);
        return principalTeachingActivityConverter.convertToTeacherResourceJoinReportData(po);
    }

    private List<TeacherStudentJoinResourceDetailReportData> getTeacherStudentJoinResourceDetailReportData(ReportGenerateParameter parameter) {
        LambdaQueryWrapper<TeacherTeachingActivityResourceJoinDetailPO> wrapper = SqlUtil.queryWrapper(parameter,
                                                                                                       w -> w.eq(CommonDimensionEntity::getCodeType, parameter.getCodeType())
                                                                                                               .eq(CommonDimensionEntity::getDateCode, parameter.getDateCode())
                                                                                                               .eq(TeacherTeachingActivityResourceJoinDetailPO::getTeachingActivity, "学生活动"),
                                                                                                       TeacherTeachingActivityResourceJoinDetailPO.class);
        List<TeacherTeachingActivityResourceJoinDetailPO> pos = teacherTeachingActivityResourceJoinDetailMapper.selectList(wrapper);

        return principalTeachingActivityConverter.convertToTeacherStudentTeacherResourceJoinReportData(pos);
    }


    /**
     * The enum Description level.
     */
    @Getter
    enum DescriptionLevel {
        /**
         * 1、本月，指标【开展学生活动个数 】=0，则输出：
         * 本月学生活动参与情况：本月暂未开展学生活动。
         */
        Never((joinReportData) -> Objects.isNull(joinReportData.getResourceReceiveNumber()) || joinReportData.getResourceReceiveNumber().doubleValue() == 0, (data) -> "本月暂未开展学生活动。", Collections.emptyList()),
        /**
         * 1、【以直播形式开展的学生活动个数 】>0，且【以点播形式开展的学生活动个数】=0：
         * ① 【学生活动总参与个数（直播形式开展）】=0，则输出：
         * 本月学生活动参与情况：本月共计开展了xx场学生活动，均以直播形式开展，本校教师均未参与。
         */
        Equal1((joinReportData) -> Objects.nonNull(joinReportData.getResourceReceiveNumber()) && joinReportData.getResourceReceiveNumber().doubleValue() > 0
                && joinReportData.getLiveResourceReceiveNumber().doubleValue() > 0
                && joinReportData.getVodResourceReceiveNumber().doubleValue() == 0
                && joinReportData.getLiveResourceUseNumber().doubleValue() == 0,
               (data) -> "本月共计开展了{0}场学生活动，均以直播形式开展，本校教师均未参与。",
               Collections.singletonList(
                       data -> data.getResourceReceiveNumber().toString()
               )),
        /**
         * 1、【以直播形式开展的学生活动个数 】>0，且【以点播形式开展的学生活动个数】=0：
         * ② 【学生活动总参与个数（直播形式开展）】>0，则输出：
         * 本月学生活动参与情况：本月共计开展了xx场学生活动，均以直播形式开展。本校教师共计参与了xx场，其中直播参与了xx场，回看参与了xx场，学生活动直播参与率为xx.x%，学生活动总参与率为xx.x%。
         */
        Equal2((joinReportData) -> Objects.nonNull(joinReportData.getResourceReceiveNumber()) && joinReportData.getResourceReceiveNumber().doubleValue() > 0
                && joinReportData.getLiveResourceReceiveNumber().doubleValue() > 0
                && joinReportData.getVodResourceReceiveNumber().doubleValue() == 0
                && joinReportData.getLiveResourceUseNumber().doubleValue() > 0,
               (data) -> "本月共计开展了{0}场学生活动，均以直播形式开展。本校教师共计参与了{1}场，" + joinDescription(data.getLiveResourceJoinNumber(), data.getPlayoffResourceUseNumber()) + "，学生活动直播参与率为{2}，学生活动总参与率（直播+回看）为{3}。",
               Arrays.asList(
                       data -> data.getResourceReceiveNumber().toString(),
                       data -> data.getLiveResourceUseNumber().toString(),
                       data -> NumberFormatUtil.formatPercent(data.getLiveResourceJoinRate()),
                       data -> NumberFormatUtil.formatPercent(data.getResourceUseRate())
               )),

        /**
         * （2）【以直播形式开展的学生活动个数 】>0，且【以点播形式开展的学生活动个数】>0，则输出：
         * ① 【学生活动总参与个数（直播形式开展）】=0，且【学生活动总参与个数（点播形式开展）】=0，则输出：
         * 本月学生活动参与情况：本月共计开展了xx场学生活动，其中xx场以直播形式开展，xx场以点播形式开展。本校教师均未参与。
         */
        Equal3((joinReportData) -> Objects.nonNull(joinReportData.getResourceReceiveNumber()) && joinReportData.getResourceReceiveNumber().doubleValue() > 0
                && joinReportData.getLiveResourceReceiveNumber().doubleValue() > 0
                && joinReportData.getVodResourceReceiveNumber().doubleValue() > 0
                && joinReportData.getLiveResourceUseNumber().doubleValue() == 0
                && joinReportData.getVodResourceUseNumber().doubleValue() == 0
                , (data) -> "本月共计开展了{0}场学生活动，其中{1}场以直播形式开展，{2}场以点播形式开展。本校教师均未参与。",
               Arrays.asList(
                       data -> data.getResourceReceiveNumber().toString(),
                       data -> data.getLiveResourceReceiveNumber().toString(),
                       data -> data.getVodResourceReceiveNumber().toString()
               )),

        /**
         * （2）【以直播形式开展的学生活动个数 】>0，且【以点播形式开展的学生活动个数】>0，则输出：
         * ② 【学生活动总参与个数（直播形式开展）】>0，且【学生活动总参与个数（点播形式开展）】=0，则输出：
         * 本月学生活动参与情况：本月共计开展了xx场学生活动，其中xx场以直播形式开展，xx场以点播形式开展。以直播形式开展的学生活动中，本校教师共计参与了xx场，
         * 其中直播参与了xx场，回看参与了xx场。以点播形式开展的学生活动中，本校教师均未参与。本月，本校教师学生活动直播参与率为xx.x%，总参与率为xx.x%。
         */
        Equal4((joinReportData) -> Objects.nonNull(joinReportData.getResourceReceiveNumber()) && joinReportData.getResourceReceiveNumber().doubleValue() > 0
                && joinReportData.getLiveResourceReceiveNumber().doubleValue() > 0
                && joinReportData.getVodResourceReceiveNumber().doubleValue() > 0
                && joinReportData.getLiveResourceUseNumber().doubleValue() > 0
                && joinReportData.getVodResourceUseNumber().doubleValue() == 0
                , (data) -> "本月共计开展了{0}场学生活动，其中{1}场以直播形式开展，{2}场以点播形式开展。以直播形式开展的学生活动中，" +
                "本校教师共计参与了{3}场，" + joinDescription(data.getLiveResourceJoinNumber(), data.getPlayoffResourceUseNumber()) + "。以点播形式开展的学生活动中，本校教师均未参与。本月，本" +
                "校教师学生活动直播参与率为{4}，总参与率（直播+回看）为{5}。",
               Arrays.asList(
                       data -> data.getResourceReceiveNumber().toString(),
                       data -> data.getLiveResourceReceiveNumber().toString(),
                       data -> data.getVodResourceReceiveNumber().toString(),
                       data -> data.getLiveResourceUseNumber().toString(),
                       data -> NumberFormatUtil.formatPercent(data.getLiveResourceJoinRate()),
                       data -> NumberFormatUtil.formatPercent(data.getResourceUseRate())
               )),

        /**
         * （2）【以直播形式开展的学生活动个数 】>0，且【以点播形式开展的学生活动个数】>0，则输出：
         * ③ 【学生活动总参与个数（直播形式开展）】>0，且【学生活动总参与个数（点播形式开展）】＞0，则
         * 本月学生活动参与情况：本月共计开展了xx场学生活动，其中xx场以直播形式开展，xx场以点播形式开展。以直播形式开展的学生活动中，本校
         * 教师共计参与了xx场，其中直播参与了xx场，回看参与了xx场。以点播形式开展的学生活动中，本校教师共计参与了xx场。本月，本校教师学生
         * 活动直播参与率为xx.x%，总参与率为xx.
         */
        Equal5((joinReportData) -> Objects.nonNull(joinReportData.getResourceReceiveNumber()) && joinReportData.getResourceReceiveNumber().doubleValue() > 0
                && joinReportData.getLiveResourceReceiveNumber().doubleValue() > 0
                && joinReportData.getVodResourceReceiveNumber().doubleValue() > 0
                && joinReportData.getLiveResourceUseNumber().doubleValue() > 0
                && joinReportData.getVodResourceUseNumber().doubleValue() > 0
                , (data) -> "本月共计开展了{0}场学生活动，其中{1}场以直播形式开展，{2}场以点播形式开展。以直播形式开展的学生活动中，本校" +
                "教师共计参与了{3}场，" + joinDescription(data.getLiveResourceJoinNumber(), data.getPlayoffResourceUseNumber()) + "。以点播形式开展的学生活动中，本校教师共计参与了{4}场。本月，本校教" +
                "师学生活动直播参与率为{5}，总参与率（直播+回看）为{6}。",
               Arrays.asList(
                       data -> data.getResourceReceiveNumber().toString(),
                       data -> data.getLiveResourceReceiveNumber().toString(),
                       data -> data.getVodResourceReceiveNumber().toString(),
                       data -> data.getLiveResourceUseNumber().toString(),
                       data -> data.getVodResourceUseNumber().toString(),
                       data -> NumberFormatUtil.formatPercent(data.getLiveResourceJoinRate()),
                       data -> NumberFormatUtil.formatPercent(data.getResourceUseRate())
               )),

        /**
         * （2）【以直播形式开展的学生活动个数 】>0，且【以点播形式开展的学生活动个数】>0，则输出：
         * ④ 【学生活动总参与个数（直播形式开展）】=0，且【学生活动总参与个数（点播形式开展）】＞0，则输出：
         * 本月学生活动参与情况：本月共计开展了xx场学生活动，其中xx场以直播形式开展，xx场以点播形式开展。以直播形式开展的学生活动中，本校
         * 教师均未参与。以点播形式开展的学生活动中，本校教师共计参与了xx场。本月，本校教师学生活动直播参与率为xx.x%，总参与率为xx.x%。
         */
        Equal6((joinReportData) -> Objects.nonNull(joinReportData.getResourceReceiveNumber()) && joinReportData.getResourceReceiveNumber().doubleValue() > 0
                && joinReportData.getLiveResourceReceiveNumber().doubleValue() > 0
                && joinReportData.getVodResourceReceiveNumber().doubleValue() > 0
                && joinReportData.getLiveResourceUseNumber().doubleValue() == 0
                && joinReportData.getVodResourceUseNumber().doubleValue() > 0
                , (data) -> "本月共计开展了{0}场学生活动，其中{1}场以直播形式开展，{2}场以点播形式开展。以直播形式开展的学生活动中，本校" +
                "教师均未参与。以点播形式开展的学生活动中，本校教师共计参与了{3}场。本月，本校教师学生活动直播参与率为{4}，总参与率（直播+回看）为{5}。",
               Arrays.asList(
                       data -> data.getResourceReceiveNumber().toString(),
                       data -> data.getLiveResourceReceiveNumber().toString(),
                       data -> data.getVodResourceReceiveNumber().toString(),
                       data -> data.getVodResourceUseNumber().toString(),
                       data -> NumberFormatUtil.formatPercent(data.getLiveResourceJoinRate()),
                       data -> NumberFormatUtil.formatPercent(data.getResourceUseRate())
               )),

        /**
         * （3）【以直播形式开展的学生活动个数 】=0，且【以点播形式开展的学生活动个数】>0，则输出：
         * 本月学生活动参与情况：本月共计开展了xx场学生活动，均以点播形式开展。本校教师共计参与了xx场，学生活动总参与率为xx.x%。
         */
        Equal7((joinReportData) -> Objects.nonNull(joinReportData.getResourceReceiveNumber()) && joinReportData.getResourceReceiveNumber().doubleValue() > 0
                && joinReportData.getLiveResourceReceiveNumber().doubleValue() == 0
                && joinReportData.getVodResourceReceiveNumber().doubleValue() > 0
                , (data) -> "本月学生活动参与情况：本月共计开展了{0}场学生活动，均以点播形式开展。本校教师共计参与了{1}场，学生活动总参与率（直播+回看）为{2}。",
               Arrays.asList(
                       data -> data.getResourceReceiveNumber().toString(),
                       data -> data.getVodResourceUseNumber().toString(),
                       data -> NumberFormatUtil.formatPercent(data.getResourceUseRate())
               ));
        private final Predicate<TeacherTeachingActivityResourceJoinReportData> predicate;
        private final Function<TeacherTeachingActivityResourceJoinReportData, String> description;
        private final List<Function<TeacherTeachingActivityResourceJoinReportData, String>> functions;

        DescriptionLevel(Predicate<TeacherTeachingActivityResourceJoinReportData> predicate, Function<TeacherTeachingActivityResourceJoinReportData, String> description, List<Function<TeacherTeachingActivityResourceJoinReportData, String>> functions) {
            this.predicate = predicate;
            this.description = description;
            this.functions = functions;
        }

        /**
         * Determine description string.
         *
         * @param data the data
         * @return the string
         */
        static String determineDescription(TeacherTeachingActivityResourceJoinReportData data) {
            if (Objects.isNull(data)) {
                return Never.getDescription().apply(null);
            }
            return Arrays.stream(values())
                    .filter(level -> level.getPredicate().test(data
                    ))
                    .findFirst()
                    .map(level -> MessageFormat.format(level.getDescription().apply(data), level.getFunctions().stream().map(function -> function.apply(data)).toArray()))
                    .orElse(null);
        }

    }

    private static String joinDescription(Integer liveJoinNumber, Integer playoffJoinNumber) {
        //其中直播参与了{4}场，回看参与了{5}场。
        String liveJoinDescription = MessageFormat.format("直播参与了{0}场", liveJoinNumber);
        String playoffJoinDescription = MessageFormat.format("回看参与了{0}场", playoffJoinNumber);
        return MessageFormat.format("其中{0},{1}", liveJoinDescription, playoffJoinDescription);
    }


    /**
     * The enum Description.
     */
    @Getter
    enum Description {

        /**
         * Rate description.
         */
        RATE("教师同步资源使用率", () -> {
            Map<String, String> map = Maps.newHashMap();
            map.put("never", "截止本月，本学期各学届的学科教师在学生活动环节均未使用过同步资源");
            map.put("max", "截止本月，本学期{0}学科教师在学生活动环节的同步资源使用率最高，为{1}");
            map.put("min", "；{0}学科教师在学生活动环节的同步资源使用率最低，为{1}");
            map.put("zero", "；{0}学科教师在学生活动环节暂未使用过同步资源");
            return map;
        }, NumberFormatUtil::formatPercent);

        private final String name;
        private final Supplier<Map<String, String>> supplier;
        private final Function<Number, String> format;

        Description(String name, Supplier<Map<String, String>> supplier, Function<Number, String> format) {
            this.name = name;
            this.supplier = supplier;
            this.format = format;
        }

        private String format(Number num) {
            if (Objects.isNull(this.format)) {
                return num.toString();
            }
            return this.format.apply(num);
        }


        /**
         * Create resource usage description string.
         *
         * @param usages    the usages
         * @param predicate the predicate
         * @param function  the function
         * @return the string
         */
        public String createResourceUsageDescription(List<TeacherStudentUsageReportData> usages,
                                                     Predicate<TeacherStudentUsageReportData> predicate,
                                                     Function<TeacherStudentUsageReportData, Number> function) {
            BiFunction<Map<String, String>, Function<Number, String>, String> bifunction = ReportDescriptionUtil.minAndMaxDescription(usages, predicate, function);
            return bifunction.apply(this.getSupplier().get(), this::format);
        }
    }

}
